package com.third.service.Impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.third.Listener.MailQueueListener;
import com.third.entity.Users;
import com.third.entity.vo.request.ConfirmResetVo;
import com.third.entity.vo.request.EmailRegisterVO;
import com.third.entity.vo.request.EmailResetVO;
import com.third.mapper.UsersMapper;
import com.third.service.UsersService;
import com.third.utils.Const;
import com.third.utils.FlowUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.TimeUnit;

/**
 * @author 唐博文
 * @version 2023.1.2
 * @date 2023/10/24 20:22 星期二
 */
@Service
public class UsersServiceImpl extends ServiceImpl<UsersMapper, Users> implements UsersService {
    
    @Resource
    StringRedisTemplate stringRedisTemplate;
    
    @Resource
    FlowUtils utils;
    
    @Resource
    MailQueueListener mailQueueListener;
    
    @Resource
    PasswordEncoder encoder;
    
    @Resource
    UsersMapper usersMapper;
    
    @Override
    public Users findUsersByNameOrEmail(Object text) {
        return this.query()
                .eq("username",text).or()
                .eq("email",text)
                .one();
    }
    
    @Override
    public String registerEmailUsers(EmailRegisterVO vo) {
        String email = vo.getEmail();
        String username = vo.getUsername();
        String key= Const.VERIFY_EMAIL_DATA+email;
        String code = stringRedisTemplate.opsForValue().get(key);
        System.out.println("redis中的code：：："+code);
        System.out.println("vo中的code：：："+vo.getCode());
        if(code==null) return "请先获取验证码";
        if(!code.equals(vo.getCode()))return "验证码有误，请重新输入";
        if(this.existAccountByUsername(username)) return "此用户名已被其他用户使用，请更新一个新的用户名";
        if(existUsersByEmail(email))return "此电子邮件已被其他用户注册";
        String password=encoder.encode(vo.getPassword());
        System.out.println("vo=====" + vo);
        int roleId = vo.getRoleId();
        Users users = new Users(null, vo.getUsername(), password, roleId, vo.getPhone(), vo.getAddress(), email);
        System.out.println("users====" + users);
        if(vo.getRoleId()==6) {
            if (this.save(users)) {
                stringRedisTemplate.delete(key);
                return null;
            } else {
                return "内部错误，请联系管理员";
            }
        }else {
            usersMapper.registerApp(vo.getUsername(), password , vo.getPhone(), vo.getAddress(), email,roleId);
            return null;
        }
    }

    
    //加锁线程安全，防止同一时间几百个同时用
    //.intern()可以提升性能
    @Override
    //注册电子邮件验证码
    public String registerEmailVerifyCode(String type, String email, String ip) {
        
        synchronized (ip.intern()) {
            if (!this.verifyLimit(ip))
                return "请求频繁，请稍后再试";
            Random random = new Random();
            int code = random.nextInt(899999) + 100000;
            //要放进消息队列的存起来
            Map<String, Object> data = Map.of("type", type, "email", email, "code", code);
            System.out.println("data================"+data);
            //发送邮件
            try {
                mailQueueListener.sendMailMessage(data);
            } catch (Exception e) {
                System.out.println("邮箱不存在");
                return "邮箱不存在!!!!";
            }
            /*rabbitTemplate.convertAndSend(
                                          "mail",
                                          data);*/
            //rabbitTemplate.convertAndSend("mail", data);
            stringRedisTemplate.opsForValue()
                    .set(Const.VERIFY_EMAIL_DATA + email, String.valueOf(code), 3, TimeUnit.MINUTES);
            
            return null;
        }
    }
    
    //确认重置密码的验证码
    @Override
    public String resetConfirm(ConfirmResetVo vo) {
        String email = vo.getEmail();
        String code = stringRedisTemplate.opsForValue().get(Const.VERIFY_EMAIL_DATA + email);
        if(code==null) return "请先获取验证码";
        if(!code.equals(vo.getCode())) return "验证码错误，请重新输入";
        return null;
    }
    
    @Override
    public String resetEmailUsersPassword(EmailResetVO vo) {
        String email = vo.getEmail();
        String verify = this.resetConfirm(new ConfirmResetVo(email, vo.getCode()));
        if(verify!=null) return verify;
        String password = encoder.encode(vo.getPassword());
        boolean update = this.update().eq("email", email).set("password", password).update();
        if(update)stringRedisTemplate.delete(Const.VERIFY_EMAIL_DATA+email);
        return null;
    }
    
    
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        Users account = this.findUsersByNameOrEmail(username);
        if(account==null)
            throw new UsernameNotFoundException("用户名或密码错误");
        String roleName = usersMapper.findRoleNameByUsers(account.getRoleId());
        return User
                .withUsername(account.getUsername())
                .password(account.getPassword())
                .roles(roleName)
                .build();
    }
    
    
    
    //通过邮件判断用户是否存在
    private boolean existUsersByEmail(String email){
        /*QueryChainWrapper<Users> email1 = this.query().eq("email", email);
        List<Users> users = usersMapper.selectList(email1);*/
        QueryWrapper<Users> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("email", email);
        List<Users> users = usersMapper.selectList(queryWrapper);
        return users.size() > 0;
    }
    
    //通过username判断用户是否存在
    private boolean existAccountByUsername(String username){
        List<Users> users = usersMapper.selectList(new QueryWrapper<Users>().eq("username", username));
        return users.size()>0;
    }
    
    private boolean verifyLimit(String ip){
        String key=Const.VERIFY_EMAIL_LIMIT+ip;
        return utils.limitOnceCheck(key,60);
    }
    
    
    
    
    
    
}
